//通用工具模块：提供一些通用的工具函数，如去除字符串末尾的换行符、安全复制字符串、检查字符串是否为空或只包含空白字符、检查用户名是否合法等。
#include "utils.h"
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

/**
 *  检查给定的用户名是否包含非法字符。
 * 
 * 此函数会遍历传入用户名中的每个字符，检查其是否为预定义的非法字符（*、#、/、&）。
 * 若发现非法字符，函数会立即返回 false，表示用户名无效；
 * 若遍历完所有字符都未发现非法字符，则返回 true，表示用户名有效。
 * 
 *   name 待检查的用户名，为以 null 结尾的字符串。
 *  return bool 若用户名有效（不包含非法字符）则返回 true，否则返回 false。
 */
bool is_valid_username(const char *name) {
    // 定义包含所有非法字符的字符串
    const char *invalid_chars = "*#/&";
    // 遍历用户名中的每个字符
    size_t length = strlen(name);
    for (size_t i = 0; i < length; i++) {
        // 检查当前字符是否存在于非法字符字符串中
        //strchr函数用于在字符串中查找指定字符的首次出现位置。
        //如果找到了，返回指向该位置的指针；如果未找到，返回NULL。
        //invalid_chars:要在其中进行查找的字符串。
        //name[i]:要查找的字符。
        if (strchr(invalid_chars, name[i]) != NULL) {
            // 若发现非法字符，立即返回 false
            return false;
        }
    }
    // 若未发现非法字符，返回 true
    return true;
}

/**
 *  去除字符串首尾的空白字符。
 * 
 * 该函数会修改传入的字符串，移除其开头和结尾的空白字符，
 * 包括空格、制表符、换行符等。若字符串为空或为 NULL，函数将直接返回。
 * 
 *   str 待处理的字符串。
 */
void trim_string(char *str) {
    // 检查字符串是否为 NULL 或者为空字符串，如果是则直接返回
    if (str == NULL || *str == '\0') {
        return;
    }

    // 指向字符串的起始位置
    char *start = str;
    // 指向字符串的最后一个字符位置
    char *end = str + strlen(str) - 1;  //-1是因为字符串长度不包括结束符

    // 去除字符串首部的空白字符，移动 start 指针直到遇到非空白字符
    //isspace函数检查给定的字符是否为空白字符（如空格、制表符、换行符等）。是--返回非零。不是--返回0
    //(unsigned char)*start:将start指针当前指向的字符强制转换为无符号字符。
    while (isspace((unsigned char)*start)) {
        start++;
    }

    // 去除字符串尾部的空白字符，移动 end 指针直到遇到非空白字符
    //end > start：保证end指针在start指针之后，当他俩重合时，说明已经处理完毕
    while (end > start && isspace((unsigned char)*end)) {
        end--;
    }

    // 判断start指针是否发生了移动
    // 如果 start 指针发生了移动，说明字符串开头有空白字符，
    // 需要将非空白部分移动到字符串的起始位置
    // 否则，说明字符串没有空白字符，不需要移动
    if (start != str) {
        // 使用 memmove 函数将非空白部分从 start 位置复制到 str 位置
        //str指向的是原始字符串的起始位置，
        //start指向的是处理后的非空白部分的起始位置。
        //end - start + 1：计算非空白部分的长度（包括结束符，便于后面添加）。
        memmove(str, start, end - start + 1);
    }

    // 在处理后的字符串末尾添加 null 结束符
    str[end - start + 1] = '\0';
}